package org.itzixi.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.UUID;

/**
 * 基于 JavaCV + FFmpeg 的视频工具类（支持所有格式）
 */
@Slf4j
public class FFmpegVideoUtil {

    // 存放截取的视频帧图片路径（Windows 路径）
    public static String videoFramesPath = "E:\\IdeaProjects\\wechat-dev\\pic";

    /** 图片格式 */
    private static final String FILE_EXT = "jpg";

    /** 截取的帧数（第5帧，可根据需求调整） */
    private static final int THUMB_FRAME = 5;

    /**
     * 从视频文件路径截取帧并保存
     * @param videoFilePath 视频文件路径
     * @param frameFilePath 图片保存路径
     */
    public static void fetchFrame(String videoFilePath, String frameFilePath) {
        File videoFile = new File(videoFilePath);
        File frameFile = new File(frameFilePath);
        getFirstFrame(videoFile, frameFile);
    }

    /**
     * 从 MultipartFile 截取帧并保存到目标文件
     * @param videoFile 上传的视频文件
     * @param targetFile 保存的图片文件
     */
    public static void fetchFrame(MultipartFile videoFile, File targetFile) throws IOException {
        // 创建临时文件接收上传的视频流
        File tempFile = new File(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString());
        FileUtils.copyInputStreamToFile(videoFile.getInputStream(), tempFile);

        try {
            getFirstFrame(tempFile, targetFile);
        } finally {
            // 删除临时文件
            if (tempFile.exists()) {
                tempFile.delete();
            }
        }
    }

    /**
     * 从 MultipartFile 截取帧并返回图片文件
     * @param videoFile 上传的视频文件
     * @return 截取的图片文件
     */
    public static File fetchFrame(MultipartFile videoFile) {
        String originalFilename = videoFile.getOriginalFilename();
        File targetFile = null;
        File tempFile = null;
        try {
            // 创建临时文件
            tempFile = new File(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString());
            FileUtils.copyInputStreamToFile(videoFile.getInputStream(), tempFile);

            // 生成图片文件名（保留原视频名，替换后缀为 jpg）
            int extIndex = originalFilename.lastIndexOf(".");
            String imageName = extIndex > 0
                    ? originalFilename.substring(0, extIndex) + "." + FILE_EXT
                    : UUID.randomUUID().toString() + "." + FILE_EXT;

            // 图片保存路径（视频帧目录 + 图片名）
            targetFile = new File(videoFramesPath, imageName);
            getFirstFrame(tempFile, targetFile);

        } catch (Exception e) {
            log.error("获取视频帧异常：", e);
            targetFile = null; // 出错时返回 null
        } finally {
            // 清理临时文件
            if (tempFile != null && tempFile.exists()) {
                tempFile.delete();
            }
        }
        log.debug("视频帧截取完成，图片路径：{}", targetFile);
        return targetFile;
    }

    /**
     * 核心方法：从视频文件截取指定帧并保存为图片
     * @param videoFile 视频文件
     * @param targetFile 保存的图片文件
     */
    public static void getFirstFrame(File videoFile, File targetFile) {
        FFmpegFrameGrabber grabber = null;
        try {
            // 初始化 FFmpeg 帧抓取器
            grabber = new FFmpegFrameGrabber(videoFile);
            grabber.start(); // 启动抓取器

            // 检查视频总帧数，避免截取的帧超出范围
            int totalFrames = grabber.getLengthInFrames();
            if (totalFrames <= 0) {
                log.error("视频文件无有效帧：{}", videoFile.getAbsolutePath());
                return;
            }

            // 调整截取的帧（如果总帧数小于目标帧，取最后一帧）
            int frameToGrab = Math.min(THUMB_FRAME, totalFrames - 1);
            grabber.setFrameNumber(frameToGrab); // 跳转到指定帧

            // 将 FFmpeg 帧转换为 Java  BufferedImage
            Java2DFrameConverter converter = new Java2DFrameConverter();
            BufferedImage bufferedImage = converter.convert(grabber.grabImage());
            if (bufferedImage == null) {
                log.error("无法获取视频帧：{}", videoFile.getAbsolutePath());
                return;
            }

            // 确保目标目录存在（自动创建多级目录）
            if (!targetFile.getParentFile().exists()) {
                targetFile.getParentFile().mkdirs();
            }

            // 保存图片到目标路径
            ImageIO.write(bufferedImage, FILE_EXT, targetFile);
            log.info("视频帧已保存：{}", targetFile.getAbsolutePath());

        } catch (Exception e) {
            log.error("截取视频帧失败：", e);
        } finally {
            // 释放资源（必须关闭，否则可能导致文件占用）
            if (grabber != null) {
                try {
                    grabber.stop();
                    grabber.release();
                } catch (Exception e) {
                    log.error("释放 FFmpeg 资源失败：", e);
                }
            }
        }
    }

    // 测试方法：直接运行 main 方法验证
    public static void main(String[] args) {
        // 强制打印 FFmpeg 加载日志
        System.setProperty("org.bytedeco.javacpp.logger", "DEBUG");
        System.setProperty("org.bytedeco.javacv.logger", "DEBUG");

        try {
            long startTime = System.currentTimeMillis();
            File videoFile = new File("C:\\Users\\Lenovo\\Videos\\2025-08-18 11-05-49.mkv");
            File targetFile = new File(videoFramesPath + "/test_ffmpeg.jpg");
            getFirstFrame(videoFile, targetFile);
            System.out.println("截取耗时：" + (System.currentTimeMillis() - startTime) + "ms");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}